package com.renhe.utils;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.CookieStore;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.params.ConnRoutePNames;
import org.apache.http.conn.params.ConnRouteParams;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.ssl.SSLContextBuilder;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.cookie.Cookie;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.CoreConnectionPNames;
import org.apache.http.params.CoreProtocolPNames;
import org.apache.http.protocol.HTTP;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * ApacheClicent是Apache提供的开源框架
 */
@SuppressWarnings("deprecation")
public class ApacheClientHttpFetcher {

    //private static Logger logger = LoggerFactory.getLogger(ApacheClientHttpFetcher.class);

    private DefaultHttpClient client = new DefaultHttpClient();

    private String encode = "UTF-8";

    private int sec = 20;

    private Map<String, String> defaultHeaders = new TreeMap<String, String>();

    private HttpResponse response;

    public ApacheClientHttpFetcher(){
        this.setEncoding(this.encode);
        setTimeout(this.sec);
        enableSSL();

        //默认头部
        defaultHeaders.put("Connection", "keep-alive");
        defaultHeaders.put("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
        defaultHeaders.put("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.110 Safari/537.36");
    }

    public ApacheClientHttpFetcher(String encode){
        this.setEncoding(encode);
        setTimeout(this.sec);
        
        //设置重用端口
        client.getParams().setParameter(CoreConnectionPNames.SO_REUSEADDR, true);
    }
    
    public DefaultHttpClient getClient(){
    	return client;
    }

    //重写验证方法，取消检测ssl
    private static TrustManager truseAllManager = new X509TrustManager() {
        public void checkClientTrusted(X509Certificate[] arg0, String arg1) 
                throws CertificateException {
        } 

        public void checkServerTrusted(X509Certificate[] arg0, String arg1) 
                throws CertificateException { 
        } 

        public X509Certificate[] getAcceptedIssuers() { 
            return null; 
        } 
    };

    public boolean enableSSL() {
        // 调用ssl
        try {
            SSLContext sslcontext = new SSLContextBuilder().build();
            sslcontext.init(null, new TrustManager[]{truseAllManager}, null);
            SSLSocketFactory sf = new SSLSocketFactory(sslcontext);
            sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
            Scheme https = new Scheme("https", sf, 443);
            client.getConnectionManager().getSchemeRegistry().register(https);
            return true;
        } catch (Exception e) {
            //logger.error("error", e);
            e.printStackTrace();
            return false;
        }
    }

    public HttpResponse getResponse(){
        return this.response;
    }

    public void setTimeout(int sec) {
        this.sec = sec;
        this.client.getParams().setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, sec * 1000);
        this.client.getParams().setParameter(CoreConnectionPNames.SO_TIMEOUT, sec * 1000);
    }

    public void setProxy(String ip, int port){
        HttpHost proxy = new HttpHost(ip, port);
        client.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy);
    }

    public void bind(String ip){
        try{
            InetAddress addr = InetAddress.getByName(ip);
            this.client.getParams().setParameter(ConnRouteParams.LOCAL_ADDRESS, addr);
        }catch(Exception e){
            e.printStackTrace();
        }
    }

    /* 发送请求的编码设置 */
    public void setEncoding(String encode){
        this.encode = encode;

        //设置客户端编码 
        client.getParams().setParameter(CoreProtocolPNames.HTTP_CONTENT_CHARSET, encode);
        client.getParams().setParameter("http.protocol.content-charset", encode); 
        client.getParams().setParameter(HTTP.CONTENT_ENCODING, encode); 
        client.getParams().setParameter(HTTP.CHARSET_PARAM, encode); 
        client.getParams().setParameter(HTTP.DEFAULT_PROTOCOL_CHARSET, encode); 
    }

    public void setCookie(Cookie cookie){
        CookieStore cookieStore = client.getCookieStore();
        cookieStore.addCookie(cookie);
    }

    public byte[] get(String url, Map<String, String> headMap){
        InputStream is = null;
        try {
            HttpGet httpGet = new HttpGet(url);

            // 设置头部
            if(null != headMap) {
                defaultHeaders.putAll(headMap);
            }
            for(String k : defaultHeaders.keySet()) {
                httpGet.addHeader(k, defaultHeaders.get(k));
            }

            HttpResponse response = client.execute(httpGet);
            //记录下这个response
            this.response = response;
            
            is = response.getEntity().getContent();
            ByteArrayOutputStream outSteam = new ByteArrayOutputStream();

            byte[] b = new byte[1024];
            int len = 0;
            while ((len = is.read(b)) > 0) {
                outSteam.write(b, 0, len);
            }

            byte[] content = outSteam.toByteArray();
            outSteam.close();
            return content;

        } catch (IOException e) {
            //logger.error("error", e);
            e.printStackTrace();
            return null;
        } finally{
            if(is != null){
                //try{is.close();}catch(Exception e){logger.error("error", e);}
                try{is.close();}catch(Exception e){e.printStackTrace();}
            }
        }
    }

    public byte[] get(String url){
        return get(url, null);
    }

    public String gets(String url, Map<String, String> headMap){
        byte[] bs = get(url, headMap);
        if(bs == null)
            return null;
        try{
            return new String(bs, this.encode);
        }catch(Exception e){
            //logger.error("error", e);
            e.printStackTrace();
            return null;
        }
    }

    public String gets(String url){
        return gets(url, null);
    }

    private byte[] post(String url, HttpEntity data, Map<String, String> headMap){
        InputStream is = null;
        try {
            HttpPost httppost = new HttpPost(url);
            // 设置头部
            if(null != headMap) {
                defaultHeaders.putAll(headMap);
            }
            for(String k : defaultHeaders.keySet()) {
                httppost.addHeader(k, defaultHeaders.get(k));
            }

            httppost.setEntity(data);
            // 发送请求 
            HttpResponse httpresponse = client.execute(httppost);
            //记录下这个response
            this.response = httpresponse;

            // 获取返回数据
            HttpEntity entity = httpresponse.getEntity();

            if (entity != null) { 
                is = entity.getContent();
                ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
                byte[] b = new byte[1024];
                int len = 0;
                while ((len = is.read(b)) > 0) {
                    outSteam.write(b, 0, len);
                }
                entity.consumeContent();

                byte[] content = outSteam.toByteArray();
                outSteam.close();
                return content;
            } 
            return null;
        } catch (Exception e) {
            //logger.error("error", e);
            e.printStackTrace();
            return null;
        } finally{
            if(is != null){
                //try{is.close();}catch(Exception e){logger.error("error", e);}
                try{is.close();}catch(Exception e){e.printStackTrace();}
            }
        }
    }

    public byte[] post(String url, byte[] data, Map<String, String> headMap){
        return post(url, new ByteArrayEntity(data), headMap);
    }

    public byte[] post(String url, byte[] data){
        return post(url, new ByteArrayEntity(data), null);
    }

    public byte[] post(String url, String data, Map<String, String> headMap){
        try{
            return post(url, data.getBytes("UTF-8"), headMap);
        }catch(Exception e){
            //logger.error("error", e);
            e.printStackTrace();
            return null;
        }
    }

    public byte[] post(String url, String data){
        return post(url, data, null);
    }

    public byte[] post(String url, List<NameValuePair> data, Map<String, String> headMap){
        try{
            return post(url, new UrlEncodedFormEntity(data, encode), headMap);
        }catch(Exception e){
            //logger.error("error", e);
            e.printStackTrace();
            return null;
        }
    }

    public String posts(String url, List<NameValuePair> data, Map<String, String> headMap){
        try{
            byte[] content = post(url, new UrlEncodedFormEntity(data, encode), headMap);
            if(content == null)
                return null;
            return new String(content, encode);
        }catch(Exception e){
            //logger.error("error", e);
            e.printStackTrace();
            return null;
        }
    }

    public String posts(String url, List<NameValuePair> data){
        return posts(url, data, null);
    }

    public String posts(String url, String data, Map<String, String> headMap){
        try{
            byte[] bs = post(url, data.getBytes("UTF-8"), headMap);
            if(bs == null)
                return null;
            return new String(bs, encode);
        }catch(Exception e){
            //logger.error("error", e);
            e.printStackTrace();
            return null;
        }
    }

    public String posts(String url, String data){
        return posts(url, data, null);
    }

    public void close(){
        client.getConnectionManager().shutdown();
    }
    
    public Header[] getResponseHeaders(){
    	if(this.response == null)
    		return new Header[0];
    	return this.response.getAllHeaders();
    }
}
